<?php
/**
 * Created by PhpStorm.
 * User: ZhangYinxian
 * Date: 2016-09-25
 * Time: 10:23
 */

namespace app\index\logic;
use think\Db;
/**
 * 多肽筛选逻辑代码
 * Class PeptideScreening
 * @package app\index\logic
 */
class PeptideScreening
{
    private $peptideAntisenseData1;
    private $peptideAntisenseData2;

    private $mHasError=false;
    private $mMessage;
    /**
     * 初始化反义肽库
     */
    public function initPeptideAntisense(){
        $peptide_antisense_model = Db::name('LibraryPeptideAntisense');
        $peptide_antisense_result1 = $peptide_antisense_model->where('flag=1')->select();
        $peptide_antisense_result2 = $peptide_antisense_model->where('flag=2')->select();

        $this->peptideAntisenseData1 = array2map($peptide_antisense_result1, 'single', 'full');
        $this->peptideAntisenseData2 = array2map($peptide_antisense_result2, 'single', 'full');
    }

    /**
     * 得到反义肽库的结果
     */
    public function getPeptideAntisenseResult($checkAmino, $aminoLogic){
        $amino = $checkAmino;
        $amino_logic = $aminoLogic;

        $peptide_antisense_data1 = $this->peptideAntisenseData1;
        $peptide_antisense_data2 = $this->peptideAntisenseData2;

        $valid_result = $amino_logic->analyze($amino, $peptide_antisense_data1);
        if($valid_result['has_error']){
              return $this->setMessage($valid_result['message']);
        }

        $valid_result2 = $amino_logic->analyze($amino, $peptide_antisense_data2);
        if($valid_result2['has_error']){
            return $this->setMessage($valid_result2['message']);
        }

        $amino_details = $valid_result['amino_detail'];
        $amino_details = array_reverse($amino_details);

        $amino_details2 = $valid_result2['amino_detail'];

        $antisence_count = 1;
        $replace_count = 0;
        $final_sequence = '';
        $sequences = array();
        foreach($amino_details as $amino){
            $peptide_antisense_data = $peptide_antisense_data1[$amino];
            $replace_number = $peptide_antisense_data['replace_number'];
            $antisence_count = $antisence_count * $replace_number;
            $replace_count += $replace_number;

            $final_sequence = $final_sequence . $peptide_antisense_data['collect'];

            $tmp_array = array();
            $replace_1 = $peptide_antisense_data['replace_1'];
            $replace_2 = $peptide_antisense_data['replace_2'];
            $replace_3 = $peptide_antisense_data['replace_3'];
            $replace_4 = $peptide_antisense_data['replace_4'];

            if(!is_null($replace_1)){
                array_push($tmp_array,$replace_1);
            }
            if(!is_null($replace_2)){
                array_push($tmp_array,$replace_2);
            }
            if(!is_null($replace_3)){
                array_push($tmp_array,$replace_3);
            }
            if(!is_null($replace_4)){
                array_push($tmp_array,$replace_4);
            }

            array_push($sequences, $tmp_array);
        }

        $antisence_count2 = 1;
        $replace_count2 = 0;
        $final_sequence2 = '';
        $sequences2 = array();
        foreach($amino_details2 as $amino){
            $peptide_antisense_data = $peptide_antisense_data2[$amino];
            $replace_number = $peptide_antisense_data['replace_number'];
            $antisence_count2 = $antisence_count2 * $replace_number;
            $replace_count2 += $replace_number;
            $final_sequence2 = $final_sequence2 . $peptide_antisense_data['collect'];

            $tmp_array = array();
            $replace_1 = $peptide_antisense_data['replace_1'];
            $replace_2 = $peptide_antisense_data['replace_2'];
            $replace_3 = $peptide_antisense_data['replace_3'];
            $replace_4 = $peptide_antisense_data['replace_4'];

            if(!is_null($replace_1)){
                array_push($tmp_array,$replace_1);
            }
            if(!is_null($replace_2)){
                array_push($tmp_array,$replace_2);
            }
            if(!is_null($replace_3)){
                array_push($tmp_array,$replace_3);
            }
            if(!is_null($replace_4)){
                array_push($tmp_array,$replace_4);
            }

            array_push($sequences2, $tmp_array);
        }


        $synthetise_fee = 25 * count($amino_details) * $replace_count;
        $synthetise_fee2 = 50 *count($amino_details2) * ($replace_count2-count($amino_details2)+1);


        $final_sequences = array();
        foreach($sequences as $sequence){
            if(count($final_sequences)==0){
                foreach($sequence as $amino){
                    array_push($final_sequences, array($amino));
                }
            }else{
                $tmp_sequences = array();

                foreach($final_sequences as $tmp_final_sequence){
                    foreach($sequence as $amino){
                        $tmp = $tmp_final_sequence;
                        array_push($tmp, $amino);
                        array_push($tmp_sequences, $tmp);
                    }
                }
                $final_sequences = $tmp_sequences;
            }
        }
        $final_str_sequences = array();
        foreach($final_sequences as $tmp_final_sequence){
            $str = '';
            foreach($tmp_final_sequence as $amino){
                $str = $str . $amino;
            }
            array_push($final_str_sequences, $str);
        }

        // 计算3'-5'
        $final_sequences2 = array();
        foreach($sequences2 as $sequence){
            if(count($final_sequences2)==0){
                foreach($sequence as $amino){
                    array_push($final_sequences2, array($amino));
                }
            }else{
                $tmp_sequences = array();

                foreach($final_sequences2 as $tmp_final_sequence){
                    foreach($sequence as $amino){
                        $tmp = $tmp_final_sequence;
                        array_push($tmp, $amino);
                        array_push($tmp_sequences, $tmp);
                    }
                }
                $final_sequences2 = $tmp_sequences;
            }
        }
        $final_str_sequences2 = array();
        foreach($final_sequences2 as $tmp_final_sequence){
            $str = '';
            foreach($tmp_final_sequence as $amino){
                $str = $str . $amino;
            }
            array_push($final_str_sequences2, $str);
        }

        return array(
            'has_error'=>$this->mHasError,
            'message'=>$this->mMessage,
            'detail'=>$amino_details,
            'antisense_count'=>$antisence_count,
            'synthetise_fee'=>$synthetise_fee,
            'final_sequence'=>$final_sequence,
            'sequences'=>$sequences,
            'final_sequences'=>$final_sequences,
            'final_str_sequences'=>$final_str_sequences,
            'detail2'=>$amino_details2,
            'antisense_count2'=>$antisence_count2,
            'synthetise_fee2'=>$synthetise_fee2,
            'final_sequence2'=>$final_sequence2,
            'sequences2'=>$sequences2,
            'final_sequences2'=>$final_sequences2,
            'final_str_sequences2'=>$final_str_sequences2
        );
    }

    /**
     * @param $dna dna序列
     * @return array result结果
     */
    public function getDNAResult($dna, $aminoLogic){
        $dna_pattern = '/[A|G|T|C|U]+/';
        $result = preg_match_all($dna_pattern, $dna, $items);
        $dna_correct = false;
        if($result==1 && count($items[0])==1){
            $dna_correct = true;
        }
        if($dna_correct==false){
            $this->setMessage('DNA序列中包含了AGTCU以外的字符');
            return [
                'has_error'=>$this->mHasError,
                'message'=>$this->mMessage
            ];
        }
        $dna_standard_data = [
            'A'=>'A',
            'G'=>'G',
            'T'=>'T',
            'U'=>'U',
            'C'=>'C'
        ];
        $amino_result = $aminoLogic->analyze($dna, $dna_standard_data);
        if($amino_result['has_error']){
            $this->setMessage($amino_result['message']);
            return [
                'has_error'=>$this->mHasError,
                'message'=>$this->mMessage
            ];
        }

        $original_dna = $amino_result['amino_detail'];
        $reverse_dna1 = array();
        $reverse_dna = array();

        foreach ($original_dna as $tmp_dna){
            switch ($tmp_dna){
                case 'U':
                    array_push($reverse_dna1, 'T');
                    break;
                default:
                    array_push($reverse_dna1, $tmp_dna);
                    break;
            }
        }
        foreach($reverse_dna1 as $tmp_dna){
            switch ($tmp_dna){
                case 'A':
                    array_push($reverse_dna, 'T');
                    break;
                case 'T':
                    array_push($reverse_dna, 'A');
                    break;
                case 'G':
                    array_push($reverse_dna, 'C');
                    break;
                case 'C':
                    array_push($reverse_dna, 'G');
                    break;
                default:
                    array_push($reverse_dna, $tmp_dna);
                    break;
            }
        }

        $sequence1 = '';
        $sequence2 = '';

        $library_dna_amino = Db::name('LibraryDnaAmino');
        $library_dna_amino_data = $library_dna_amino->select();
        $library_dna_amino_data_map = array2map($library_dna_amino_data, 'dna');

        $reverse_dna_count = count($reverse_dna);
        for($index=0; $index<$reverse_dna_count; $index+=3){
            $sub_dna = array_slice($reverse_dna, $index, 3);
            $str_dna = implode('', $sub_dna);
            if(isset($library_dna_amino_data_map[$str_dna])){
                $sequence1 = $sequence1 . $library_dna_amino_data_map[$str_dna]['amino'];
            }
        }

        $reverse_dna2 = array_reverse($reverse_dna);
        $reverse_dna_count2 = count($reverse_dna2);
        for($index=0; $index<$reverse_dna_count2; $index+=3){
            $sub_dna = array_slice($reverse_dna2, $index, 3);
            $str_dna = implode('', $sub_dna);
            if(isset($library_dna_amino_data_map[$str_dna])){
                $sequence2 = $sequence2 . $library_dna_amino_data_map[$str_dna]['amino'];
            }
        }

        return [
            'has_error'=>$this->mHasError,
            'message'=>$this->mMessage,
            'sequence1'=>$sequence1,
            'sequence2'=>$sequence2
        ];

    }
    
	/**
	 * 获取多位点扫描随机多肽矩阵（Random Peptide Library）
	 */
    public function getPeptideRandomResult($amino, $location, $aminoBaseData, $aminoLogic){
        if(strlen($amino)==0){
            return $this->setMessage('请输入蛋白或多肽序列');
        }
        if(strlen($location)==0){
            return $this->setMessage('请输入扫描位置的位置');
        }

        if(is_null($aminoBaseData)){
            return $this->setMessage('基础氨基酸信息为空，请先初始化');
        }

        $valid_result = $aminoLogic->analyze($amino, $aminoBaseData);
        if($valid_result['has_error']){
            return $this->setMessage($valid_result['message']);
        }

        $amino_detail = $valid_result['amino_detail'];
        $amino_length = count($amino_detail);

        $location = trim($location);
        $location = str_replace('、','\\', $location);
        $location = str_replace('（', '(', $location);
        $location = str_replace('）', ')', $location);
        $location = str_replace('，', ',', $location);

        $amino_keys = array_keys($aminoBaseData);
        $locations = explode(',', $location);
        $location_data = array();
        $max_location = 0;
        foreach($locations as $str_location){
            if(strpos($str_location, '(')==false){
                $data = array(
                    'location'=>$str_location,
                    'aminos'=>$amino_keys
                );
                //array_push($location_data, $data);
                $location_data[$str_location] = $data;
                if(intval($str_location)>$max_location){
                    $max_location = $str_location;
                }
            }else{
                $stack_result = stack($str_location);
                $location_number = substr($str_location, 0, $stack_result['start_index']);
                $content = $stack_result['content'];
                $sub_aminos = explode('\\', $content);
                foreach($sub_aminos as $sub_amino){
                    if(!isset($aminoBaseData[$sub_amino])){
                        return $this->setMessage($sub_amino.'非常见氨基酸，无法识别');
                    }
                }
                $data = array(
                    'location'=>$location_number,
                    'aminos'=>$sub_aminos
                );
                $location_data[$location_number] = $data;
                if(intval($location_number)>$max_location){
                    $max_location = $location_number;
                }
            }
        }

        if($max_location>$amino_length){
            return $this->setMessage('扫描位置'.$max_location.'超出了序列的长度，请确认');
        }
        $sequences = array();
        $array_sequences = array();

        $sequence_count = 0;
        $sequence_message = '';
        $location_count = count($location_data);
        if($location_count==0){
            $show_sequence = false;
            $show_all = false;
        }else if($location_count>0 && $location_count<=3){
            $show_sequence = true;
            $show_all = true;
            $sequence_count = 1;
            foreach($location_data as $data){
                $aminos = $data['aminos'];
                $sequence_count *= count($aminos);
            }


            /*
            for($index=0; $index<$sequence_count; $index++){
                $details = array();
                foreach($amino_detail as $amino){
                    $tmp = array(
                        'type'=>0,
                        'amino'=>$amino,
                        'final_amino'=>$amino
                    );
                    array_push($details, $tmp);
                }
                array_push($array_sequences, $details);
            }
            */
        }else{
            $show_sequence = true;
            $show_all = false;
            $sequence_message = '扫描位置超过3个，与技术员联系';
            $sequence_count = 1;
            foreach($location_data as $data){
                $aminos = $data['aminos'];
                $sequence_count *= count($aminos);
            }
        }

        if($show_sequence && $show_all){
            krsort($location_data);

            //初始化第一个array_sequence
            $tmp_details = array();
            foreach($amino_detail as $index=>$detail){
                $tmp = array(
                    'type'=>0,
                    'amino'=>$detail
                );
                array_push($tmp_details, $tmp);
            }
            array_push($array_sequences, $tmp_details);

            // 填充所有数据
            foreach($location_data as $data_location){
                $location_number = $data_location['location'];
                $aminos = $data_location['aminos'];
                $tmp_array_sequences = array();
                foreach($aminos as $amino){
                    foreach($array_sequences as $tmp_sequence){
                        $tmp_sequence[$location_number-1]['type']=1;
                        $tmp_sequence[$location_number-1]['amino']=$amino;
                        array_push($tmp_array_sequences, $tmp_sequence);
                    }
                }
                $array_sequences = $tmp_array_sequences;
            }

            foreach ($array_sequences as $array_sequence){
                $tmp_sequence = '';
                foreach ($array_sequence as $amino_data){
                    $type = $amino_data['type'];
                    if($type==1){
                        $tmp_sequence = $tmp_sequence . '<span style="color:red">' . $amino_data['amino']. '</span>';
                    }else{
                        $tmp_sequence = $tmp_sequence . $amino_data['amino'];
                    }
                }
                array_push($sequences, $tmp_sequence);
            }
        }
        return [
            'has_error'=>$this->mHasError,
            'message'=>$this->mMessage,
            'amino_length'=>$amino_length,
            'sequence_count'=>$sequence_count,
            'show_sequence'=>$show_sequence,
            'show_all'=>$show_all,
            'sequences'=>$sequences,
            'array_sequences'=>$array_sequences,
            'sequence_message'=>$sequence_message
        ];
    }

    /**
     * 首尾相搭多肽矩阵（Overlapping Peptide Library）
     * @param $checkAmino string 输入的蛋白或多肽序列
     * @param $m int 步移
     * @param $n int 目标多肽长度
     * @param $aminoBaseData array 氨基酸基础数据
     * @param $aminoLogic object 氨基酸识别的类
     * @return array 结果
     */
    public function getPeptideOverlappingResult($checkAmino, $m, $n, $aminoBaseData, $aminoLogic){
        $checkAmino = trim($checkAmino);
        $m = trim($m);
        $n = trim($n);
        if(count($checkAmino)==0){
            return $this->setMessage('请输入蛋白或多肽序列');
        }
        if(count($m)==0 || !is_numeric($m)){
            return $this->setMessage('请输入正确的步移');
        }
        if (count($n)==0 || !is_numeric($n)){
            return $this->setMessage('请输入正确的目标多肽长度');
        }

        $valid_result = $aminoLogic->analyze($checkAmino, $aminoBaseData);
        if($valid_result['has_error']){
            return $this->setMessage($valid_result['message']);
        }

        $amino_details = $valid_result['amino_detail'];
        $amino_length = count($amino_details);

        $tmp_sequence_count = ($amino_length - $n) / $m + 1;
        $sequence_count = intval($tmp_sequence_count) ;

        if($sequence_count<$tmp_sequence_count){
            $sequence_count += 1;
        }
        $array_sequences = array();
        $sequences = array();

        for($index=0; $index<$amino_length; $index+=$m){
            $start_index = $index;

            $sub_details = array_slice($amino_details, $start_index, $n);
            $sub_details_count = count($sub_details);

            $is_last = false;
            // 当字符串长度小于指定长度时，需要重新取，同时也是最后一个。
            if($sub_details_count<$n){
                $plus = $n - $sub_details_count;
                $start_index = $index - $plus;
                $sub_details = array_slice($amino_details, $start_index, $n);
                $is_last = true;
            }
            // 条件2,当字符串已经取到最后一个子字符串时，也将结束
            if(($index+$n) == $amino_length){
                $is_last = true;
            }
            $data = array(
                'pre'=>$start_index,
                'details'=>$sub_details,
                'content'=>implode('', $sub_details),
                'last'=>$amino_length - $start_index - $n
            );
            array_push($array_sequences, $data);
            array_push($sequences, $data);
            if($is_last) break;
        }
        return [
            'has_error'=>$this->mHasError,
            'message'=>$this->mMessage,
            'amino_length'=>$amino_length,
            'sequence_count'=>$sequence_count,
            'sequences'=>$sequences,
            'array_sequences'=>$array_sequences
        ];
    }

    /**
     * 截头多肽矩阵（Truncation Peptide Library）结果
     * @param $checkAmino string 蛋白或多肽序列
     * @param $a int n端截头数
     * @param $b int c端截头数
     * @param $destLength int 目标多肽长度
     * @param $aminoBaseData array 氨基酸基础数据
     * @param $aminoLogic object 氨基酸识别类
     */
    public function getPeptideTruncationResult($checkAmino, $a, $b, $destLength, $aminoBaseData, $aminoLogic){
        $checkAmino = trim($checkAmino);
        $a = trim($a);
        $b = trim($b);
        $destLength = trim($destLength);
        if(count($checkAmino)==0){
            return $this->setMessage('请输入蛋白或多肽序列');
        }
        if(count($a)==0 || !is_numeric($a)){
            return $this->setMessage('请输入正确的n端截头数目');
        }
        if (count($b)==0 || !is_numeric($b)){
            return $this->setMessage('请输入正确的c端截头数目');
        }

        if($a==0 && $b==0){
            return $this->setMessage('两端截头数目不能同时为0');
        }
        if(count($destLength)==0 || !is_numeric($destLength) || $destLength<=0){
            return $this->setMessage('请输入正确的最短目标多肽长度');
        }

        $valid_result = $aminoLogic->analyze($checkAmino, $aminoBaseData);
        if($valid_result['has_error']){
            return $this->setMessage($valid_result['message']);
        }

        $amino_details = $valid_result['amino_detail'];
        $amino_length = count($amino_details);
        $sequence_count = intval(($amino_length - $destLength) / ($a+$b));

        $sequences = array();
        $array_sequences = array();

        $current_detail = $amino_details;
        $index=1;
        while (true){
            $current_detail_count = count($current_detail);
            $tmp_detail = array_slice($current_detail, $a, $current_detail_count - $a - $b );
            $tmp_sequence = array(
                'pre'=>$index * $a,
                'details'=>$tmp_detail,
                'last'=>$index*$b
            );
            $index++;
            if(count($tmp_detail)<$destLength) break;
            array_push($sequences, $tmp_sequence);
            $current_detail = $tmp_detail;
        }
        return [
            'has_error'=>$this->mHasError,
            'message'=>$this->mMessage,
            'amino_length'=>$amino_length,
            'sequence_count'=>$sequence_count,
            'sequences'=>$sequences,
            'array_sequences'=>$array_sequences
        ];
    }

    /**
     * Ala筛选矩阵(Alanine Peptide Scanning Library)
     * @param $checkAmino string 蛋白或多肽序列
     * @param $aminoBaseData array 氨基酸基础数据
     * @param $aminoLogic object 氨基酸识别类
     * @return array 结果对象
     */
    public function getPeptideAlanineResult($checkAmino, $aminoBaseData, $aminoLogic){
        $checkAmino = trim($checkAmino);
        if(count($checkAmino)==0){
            return $this->setMessage('请输入蛋白或多肽序列');
        }

        if(is_null($aminoBaseData)){
            return $this->setMessage('请初始化氨基酸基础信息');
        }

        $valid_result = $aminoLogic->analyze($checkAmino, $aminoBaseData);
        if($valid_result['has_error']){
            return $this->setMessage($valid_result['message']);
        }

        $amino_detail = $valid_result['amino_detail'];
        $amino_length = count($amino_detail);
        $sequences = array();
        foreach($amino_detail as $index=>$amino){
            if($amino!='A'){
               $tmp_detail = $amino_detail;
                $tmp_detail[$index] = '<span style="color:red">A</span>';
                array_push($sequences, implode('', $tmp_detail));
            }
        }

        $sequence_count = count($sequences);

        return [
            'has_error'=>$this->mHasError,
            'message'=>$this->mMessage,
            'amino_length'=>$amino_length,
            'sequence_count'=>$sequence_count,
            'sequences'=>$sequences
        ];
    }

    /**
     * 扰序多肽矩阵（Scrambled Peptide Library）
     * @param $checkAmino string 蛋白或多肽序列
     * @param $location string 扰序位置
     * @param $aminoBaseData array 氨基酸基础数据
     * @param $aminoLogic array 氨基酸转换类
     * @return array 结果
     */
    public function getPeptideScrambledResult($checkAmino, $location, $aminoBaseData, $aminoLogic){
        $checkAmino = trim($checkAmino);
        if(count($checkAmino)==0){
            return $this->setMessage('请输入蛋白或多肽序列');
        }

        if(is_null($aminoBaseData)){
            return $this->setMessage('请初始化氨基酸基础信息');
        }

        $location_data = array();
        $max_location = 0;
        if(strlen($location)>0){
            $location = str_replace('，', ',', trim($location));
            $locations = explode(',', $location);
            foreach ($locations as $tmp_location){
                if(is_numeric($tmp_location)){
                    array_push($location_data, $tmp_location);
                    $max_location = ($tmp_location>$max_location) ? $tmp_location : $max_location;
                }else{
                    return $this->setMessage('输入的扰乱位置不是数字，请检查');
                }
            }
        }

        $valid_result = $aminoLogic->analyze($checkAmino, $aminoBaseData);
        if($valid_result['has_error']){
            return $this->setMessage($valid_result['message']);
        }

        $amino_detail = $valid_result['amino_detail'];
        $amino_length = count($amino_detail);

        if($max_location>$amino_length){
            return $this->setMessage('最大扰序位置超出序列长度');
        }

        $has_location = false;
        $amino_count_details = array();
        // 当存在指定扰序的位置时，需要获取指定位置的氨基酸
        $sub_amino_detail = [];

        if(strlen($location)==0){
            foreach($amino_detail as $tmp_amino){
                if(isset($amino_count_details[$tmp_amino])){
                    $amino_count_details[$tmp_amino]++;
                }else{
                    $amino_count_details[$tmp_amino] = 1;
                }
            }
        }else{
            if(count($location_data)==1){
                return $this->setMessage('扰序位置只有1个，无需计算');
            }

            $has_location = true;
            foreach ($location_data as $tmp_location){
                array_push($sub_amino_detail, $amino_detail[$tmp_location-1]);
            }
        }


        if($has_location){
            $detail_count =1;
            $amino_count_details = [];
            foreach ($sub_amino_detail as $sub_amino){
                if(isset($amino_count_details[$sub_amino])){
                    $amino_count_details[$sub_amino]++;
                }else{
                    $amino_count_details[$sub_amino] = 1;
                }
            }

            foreach($amino_count_details as $count_detail){
                $detail_count *= factorial($count_detail);
            }

            $sequence_count = factorial(count($sub_amino_detail)) / $detail_count;
            $sequences = array();

            $sequence_result = [];
            permute($sequence_result, $sub_amino_detail);
            foreach ($sequence_result as $tmp_sequence_detail){
                $tmp_amino_detail = $amino_detail;
                foreach ($location_data as $index=>$tmp_location){
                    $tmp_amino_detail[$tmp_location-1] = $tmp_sequence_detail[$index];
                }
                array_push($sequences, implode('', $tmp_amino_detail));
            }

            $sequence_show = '';
            $real_sequence_count = $sequence_count;
            if($sequence_count>1000){
                $sequence_show = '多肽序列过多，目前只显示'.count($sequences).'条';
                $real_sequence_count = count($sequences);
            }
        }else{
            $detail_count =1;
            foreach($amino_count_details as $count_detail){
                $detail_count *= factorial($count_detail);
            }

            $sequence_count = factorial($amino_length) / $detail_count;
            $sequences = array();

            $sequence_result = [];
            permute($sequence_result, $amino_detail);
            foreach ($sequence_result as $tmp_sequence_detail){
                array_push($sequences, implode('', $tmp_sequence_detail));
            }

            $sequence_show = '';
            $real_sequence_count = $sequence_count;
            if($sequence_count>1000){
                $sequence_show = '多肽序列过多，目前只显示'.count($sequences).'条';
                $real_sequence_count = count($sequences);
            }
        }

        return [
            'has_error'=>$this->mHasError,
            'message'=>$this->mMessage,
            'amino_length'=>$amino_length,
            'sequence_count'=>$sequence_count,
            'real_sequence_count'=>$real_sequence_count,
            'sequence_show'=>$sequence_show,
            'sequences'=>$sequences
        ];
    }

    /**
     * 单位点扫描矩阵(Positional Scanning Peptide Library)
     * @param $checkAmino string 蛋白或多肽序列
     * @param $location string 扫描位置
     * @param $aminoBaseData array 基础数据
     * @param $aminoLogic object 识别类
     * @return array 结果
     */
    public function getPeptidePositionalResult($checkAmino, $location, $aminoBaseData, $aminoLogic)
    {
        if (strlen($checkAmino) == 0) {
            return $this->setMessage('请输入蛋白或多肽序列');
        }

        if (is_null($aminoBaseData)) {
            return $this->setMessage('基础氨基酸信息为空，请先初始化');
        }

        $valid_result = $aminoLogic->analyze($checkAmino, $aminoBaseData);
        if ($valid_result['has_error']) {
            return $this->setMessage($valid_result['message']);
        }

        $amino_detail = $valid_result['amino_detail'];
        $amino_length = count($amino_detail);

        $location_data = array();
        $max_location = 0;

        $amino_keys = array_keys($aminoBaseData);

        if (strlen($location) > 0) {
            for ($index = 0; $index < $amino_length; $index++) {
                $data = array(
                    'location' => $index,
                    'aminos' => []
                );
                array_push($location_data, $data);
            }
            $location = trim($location);
            $location = str_replace('、', '\\', $location);
            $location = str_replace('（', '(', $location);
            $location = str_replace('）', ')', $location);
            $location = str_replace('，', ',', $location);
            $locations = explode(',', $location);

            foreach ($locations as $str_location) {
                if (strpos($str_location, '(') == false) {
                    if($str_location<1) {
                        return $this->setMessage($str_location . '小于1，位置不存在');
                    }
                    $data = array(
                        'location' => $str_location-1,
                        'aminos' => $amino_keys
                    );
                    $location_data[$str_location-1] = $data;
                    if (intval($str_location) > $max_location) {
                        $max_location = $str_location;
                    }
                } else {
                    $stack_result = stack($str_location);
                    $location_number = substr($str_location, 0, $stack_result['start_index']);
                    if($location_number<1){
                        return $this->setMessage($location_number . '小于1，位置不存在');
                    }

                    $content = $stack_result['content'];
                    $sub_aminos = explode('\\', $content);
                    foreach ($sub_aminos as $sub_amino) {
                        if (!isset($aminoBaseData[$sub_amino])) {
                            return $this->setMessage($sub_amino . '非常见氨基酸，无法识别');
                        }
                    }
                    $data = array(
                        'location' => $location_number-1,
                        'aminos' => $sub_aminos
                    );
                    $location_data[$location_number-1] = $data;
                    if (intval($location_number) > $max_location) {
                        $max_location = $location_number;
                    }
                }
            }
        }else{
            for ($index = 0; $index < $amino_length; $index++) {
                $data = array(
                    'location' => $index,
                    'aminos' => $amino_keys
                );
                array_push($location_data, $data);
            }
        }

        if ($max_location > $amino_length) {
            return $this->setMessage('扫描位置' . $max_location . '超出了序列的长度，请确认');
        }

        $sequence_count = 0;
        $sequences = [];
        foreach ($location_data as $tmp_location){
            $aminos = $tmp_location['aminos'];
            $sequence_count += count($aminos);

            $amino_location = $tmp_location['location'];
            foreach($aminos as $amino){
                $tmp_amino_detail = $amino_detail;
                $tmp_amino_detail[$amino_location] = '<span style="color:red">'.$amino.'</span>';
                array_push($sequences, implode('', $tmp_amino_detail));
            }
        }

        return [
            'has_error' => $this->mHasError,
            'message' => $this->mMessage,
            'amino_length' => $amino_length,
            'sequence_count' => $sequence_count,
            'sequences' => $sequences
        ];

    }

    /**
     * T细胞截头肽库矩阵(T-cell truncated library)
     * @param $checkAmino string 蛋白或多肽序列
     * @param $destLength int 目标多肽长度
     * @param $aminoBaseData array 氨基酸基础数据
     * @param $aminoLogic object 氨基酸分析类
     * @return array 结果
     */
    public function getPeptideTCellResult($checkAmino, $destLength, $aminoBaseData, $aminoLogic){
        if(strlen($checkAmino)==0){
            return $this->setMessage('请输入蛋白或多肽序列');
        }
        if(!is_numeric($destLength) || $destLength<10 || $destLength>25){
            return $this->setMessage('请输入正确的目标多肽长度，长度为10-25');
        }
        if(is_null($aminoBaseData)){
            return $this->setMessage('氨基酸基础为空，请先初始化');
        }

        $valid_result = $aminoLogic->analyze($checkAmino, $aminoBaseData);
        if($valid_result['has_error']){
            return $this->setMessage($valid_result['message']);
        }

        $amino_detail = $valid_result['amino_detail'];

        $amino_length = count($amino_detail);
        $sequence_group = $amino_length - $destLength + 1;
        if ($sequence_group<0){
            return $this->setMessage('蛋白或多肽序列过短，无法计算');
        }
        $sequence_count = $sequence_group * 4;
        $sequences = [];
        for($index=0; $index<$amino_length; $index++){
            $is_last = false;
            $sub_amino_detail = array_slice($amino_detail, $index, $destLength);
            if(count($sub_amino_detail)<$destLength){
                $is_last = true;
            }
            if ($is_last) break;

            $last = $amino_length - $index - $destLength;
            for($i=0; $i<4; $i++){
                $data = [
                    'group'=>$index,
                    'pre'=>$index+$i,
                    'details'=>array_slice($sub_amino_detail, $i),
                    'last'=>$last
                ];
                array_push($sequences, $data);
            }
        }

        return [
            'has_error' => $this->mHasError,
            'message' => $this->mMessage,
            'amino_length' => $amino_length,
            'sequence_count' => $sequence_count,
            'sequence_group'=>$sequence_group,
            'sequences' => $sequences
        ];
    }
    private function setMessage($message, $hasError=true){
        $this->mHasError = $hasError;
        $this->mMessage = $message;

        return array(
            'has_error'=>$this->mHasError,
            'message'=>$this->mMessage
        );
    }
}